package com.hnd.springframework.beans.factory.support;

import cn.hutool.core.bean.BeanUtil;
import com.hnd.springframework.beans.BeanException;
import com.hnd.springframework.beans.PropertyValue;
import com.hnd.springframework.beans.PropertyValues;
import com.hnd.springframework.beans.factory.config.BeanDefinition;
import com.hnd.springframework.beans.factory.config.BeanReference;

import java.lang.reflect.Constructor;

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {

    InstantitationStraegy instantitationStraegy = new CglibSubclassingInstanntiationStrategy();


    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object... args) throws BeanException {
        Object bean = getSingleton(beanName);
        if (bean != null) {
            return bean;
        }
        bean = createBeanInstance(beanName, beanDefinition, args);
        applyProperValues(bean, beanDefinition);
        addSingleton(beanName, bean);
        return bean;
    }

    protected Object createBeanInstance(String beanName, BeanDefinition beanDefinition, Object... args) {

        if (args == null) {
            return instantitationStraegy.instantiate(beanName, beanDefinition, null, args);
        }
        Constructor[] constructors = beanDefinition.getBeanClass().getConstructors();
        Constructor constructorTouse = null;
        for (Constructor ctor : constructors) {
            if (ctor.getParameterTypes().length == args.length) {
                constructorTouse = ctor;
                break;
            }
        }


        return instantitationStraegy.instantiate(beanName, beanDefinition, constructorTouse, args);
    }

    protected void applyProperValues(Object bean, BeanDefinition beanDefinition) {
        PropertyValues pvs = beanDefinition.getPropertyValues();
        if (pvs.getPropertyValueList().length == 0) {
            return;
        }
        for (PropertyValue pv : pvs.getPropertyValueList()) {
            Object value = pv.getValue();
            if (pv.getValue() instanceof BeanReference) {
                value = getBean(((BeanReference) pv.getValue()).getBeanName());
            }
            BeanUtil.setFieldValue(bean, pv.getName(), value);
        }

    }
}
